package com.sdy.dcsb.web.controller.inboundservice;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sdy.common.model.BizException;
import com.sdy.common.model.Response;
import com.sdy.common.utils.Assert;
import com.sdy.dcsb.biz.constants.OtherConstants;
import com.sdy.dcsb.biz.model.*;
import com.sdy.dcsb.biz.model.dto.EsbScriptDto;
import com.sdy.dcsb.biz.service.*;
import com.sdy.dcsb.biz.util.ParamDicCacheUtil;
import com.sdy.dcsb.web.callable.HttpEncapsulationCallable;
import com.sdy.dcsb.web.util.JsonUtil;
import com.sdy.mvc.controller.BaseController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 实现封装功能的api
 * @author Snaky
 */
@Slf4j
@Controller
@RequestMapping(OtherConstants.PATH_ENCAPSULATION_REQUEST_MAPPING)
public class HttpEncapsulationController extends BaseController {

    @Autowired
    private EsbEncapsulationService encapsulationService;
    @Autowired
    private EsbEncapsulationRelateService encapsulationRelateService;
    @Autowired
    private EsbEncapsulationThreadService encapsulationThreadService;
    @Autowired
    private EsbEncapsulationParamConfService paramConfService;
    @Autowired
    private EsbInboundParamService inboundParamService;
    @Autowired
    private EsbInboundMainService inboundMainService;
    @Autowired
    private EsbInboundHttpService inboundHttpService;
    @Autowired
    private EsbScriptService scriptService;
    @Autowired
    private EsbDictionaryService dictionaryService;
    @Autowired
    private ParamDicCacheUtil cacheUtil;

    @Value("${server.port}")
    private String port;

    @PostMapping(value = "/{code}", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public Response encapsulation(HttpServletRequest request, @PathVariable("code") String code, @RequestBody JSONObject json) throws Exception {
        Assert.isBlank(code, "url is empty");
        // 校验code是否符合规范
        if(!code.startsWith(OtherConstants.STANDARD_ENCAPSULATION_SERVICE_CODE_PREFIX)){
            return Response.error("接口地址错误");
        }
        if(!code.endsWith(OtherConstants.STANDARD_ENCAPSULATION_SERVICE_CODE_SUFFIX)){
            return Response.error("接口地址错误");
        }
        String baseCode = code.substring(OtherConstants.STANDARD_ENCAPSULATION_SERVICE_CODE_PREFIX.length(),
                code.length() - OtherConstants.STANDARD_ENCAPSULATION_SERVICE_CODE_SUFFIX.length());
        // 校验code是否存在
        QueryWrapper<EsbEncapsulation> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("service_code",baseCode);
        EsbEncapsulation esbEncapsulation = encapsulationService.getOne(wrapper1);
        Assert.isNull(esbEncapsulation,"接口地址错误");
        if(esbEncapsulation.getState().equals(2)){
            throw new BizException("接口已下线");
        }

        // 查询关联接口信息
        QueryWrapper<EsbEncapsulationRelate> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("encapsulation_id",esbEncapsulation.getId());
        List<EsbEncapsulationRelate> encapsulationRelates = encapsulationRelateService.list(wrapper2);

        // 查询线程配置信息
        QueryWrapper<EsbEncapsulationThread> wrapper3 = new QueryWrapper<>();
        wrapper3.eq("encapsulation_id",esbEncapsulation.getId())
            .orderByAsc("thread_order","sequence");
        List<EsbEncapsulationThread> threads = encapsulationThreadService.list(wrapper3);

        // 查询入参关联信息
        QueryWrapper<EsbEncapsulationParamConf> wrapper4 = new QueryWrapper<>();
        wrapper4.eq("encapsulation_id",esbEncapsulation.getId())
                .orderByAsc("thread_order","id");
        List<EsbEncapsulationParamConf> paramConfList = paramConfService.list(wrapper4);

        // 查询接口所有入参
        QueryWrapper<EsbInboundParam> wrapper5 = new QueryWrapper<>();
        List<Integer> serviceIds = new ArrayList<>();
        for (EsbEncapsulationRelate relate: encapsulationRelates) {
            serviceIds.add(relate.getServiceId());
        }
        wrapper5.in("service_id",serviceIds)
            .eq("param_mode",1)
            .orderByAsc("service_id","param_format","param_type","id");
        List<EsbInboundParam> inboundParams = inboundParamService.list(wrapper5);

        // 查询接口所有出参
        QueryWrapper<EsbInboundParam> wrapper6 = new QueryWrapper<>();
        wrapper6.in("service_id",serviceIds)
                .eq("param_mode",2)
                .orderByAsc("service_id","param_format","param_type","id");
        List<EsbInboundParam> outputInboundParams = inboundParamService.list(wrapper6);
        Map<Integer, List<EsbInboundParam>> groupMap = outputInboundParams.stream().collect(Collectors.groupingBy(EsbInboundParam::getServiceId));


        // 查询所有接口访问方式 get/post
        QueryWrapper<EsbInboundHttp> wrapper7 = new QueryWrapper<>();
        wrapper7.in("serviceid",serviceIds);
        List<EsbInboundHttp> inboundHttpList = inboundHttpService.list(wrapper7);

        // 查询所有需要的出参
        List<EsbInboundParam> outputInboundParamList = inboundParamService.getOutputParamConf(esbEncapsulation.getId());

        Map<Integer, List<Integer>> threadsServiceIdsList = getThreadsServiceIdsList(threads);
        Map<Integer,List<EsbInboundParam>> inputParamsMap = getParamsMapsList(json,serviceIds,inboundParams);

        // 查询接口url
        Map<Integer, String> urlMap = new HashMap<>(serviceIds.size());
        Map<Integer, String> overtimeMap = new HashMap<>(serviceIds.size());
        QueryWrapper<EsbInboundMain> wrapper8 = new QueryWrapper<>();
        wrapper8.in("serviceid",serviceIds);
        List<EsbInboundMain> esbInboundMains = inboundMainService.list(wrapper8);

        for (EsbInboundMain inboundMain: esbInboundMains) {
            overtimeMap.put(inboundMain.getServiceid(),inboundMain.getOverTime());
            String url = "http://localhost:".concat(port) + "/DCSBWeb/servlets/" +
                    inboundMain.getServcode() + "@" + inboundMain.getServversion();
            urlMap.put(inboundMain.getServiceid(),url);
        }

        // 查询接口脚本信息
        List<EsbScriptDto> scriptDtoList = scriptService.getAllScriptByEncapsulationId(esbEncapsulation.getId());
        Map<Integer, EsbScriptDto> scriptDtoMap = scriptDtoList.stream().collect(Collectors.toMap(EsbScriptDto::getServiceId, esbScriptDto -> esbScriptDto));


        // 创建线程池查询接口
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("query-pool-%d").build();
        ExecutorService pool = new ThreadPoolExecutor(threads.size(), threads.size(),0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(), threadFactory);
        // 返回结果集
        List<Future<Response>> futureList = new ArrayList<>();

        Map<String, String> allParamDic = cacheUtil.getAllParamDic();
        List<Integer> distinctThreadOrder = new ArrayList<>();
        for (EsbEncapsulationThread thread: threads) {
            Integer threadOrder = thread.getThreadOrder();
            if(!distinctThreadOrder.contains(threadOrder)){
                // 查询参数字典关联信息
                List<EsbInboundParamDic> dictionaryParamIds = dictionaryService.getExistDictionaryParamId(esbEncapsulation.getId(),threadOrder);
                Map<Integer, String> collect = dictionaryParamIds.stream().collect(Collectors.toMap(EsbInboundParamDic::getParamId, EsbInboundParamDic::getDicName));

                HttpEncapsulationCallable callable = new HttpEncapsulationCallable(threadsServiceIdsList.get(threadOrder),
                        inboundHttpList,urlMap,overtimeMap,inputParamsMap,groupMap,paramConfList,outputInboundParamList,
                        scriptDtoMap,collect,allParamDic);
                futureList.add(pool.submit(callable));
                distinctThreadOrder.add(threadOrder);
            }

        }
        pool.shutdown();
        while (true) {
            if (pool.isTerminated()) {
                if (futureList.size() > 0) {
                    Future<Response> firstFuture = futureList.get(0);
                    JSONArray result = null;
                    if(firstFuture != null){
                        Response response = firstFuture.get();
                        if(futureList.size() == 1){
                            return response;
                        }
                        if(!response.getSuccess()){
                            return response;
                        }
                        result = (JSONArray) response.getData();
                        if(result == null || result.size() == 0){
                            return response;
                        }
                    }
                    for (int i = 1; i < futureList.size(); i++) {
                        Future<Response> futureI = futureList.get(i);
                        if(futureI != null){
                            Response response = futureI.get();
                            if(!response.getSuccess()){
                                return response;
                            }
                            JSONArray futureResult = (JSONArray) response.getData();
                            if(futureResult != null && futureResult.size() > 0){
                                result = JsonUtil.mergeArray(result,futureResult);
                            }
                        }
                    }
                    if(result != null && result.size() > 0){
                        return Response.success(result);
                    }
                    return Response.error("暂未查询到数据");
                }
                return Response.error("查询异常");
            }
        }
    }

    /**
     * 获取线程中关联的接口id数组集合
     */
    private Map<Integer, List<Integer>> getThreadsServiceIdsList(List<EsbEncapsulationThread> threads){
        Map<Integer, List<Integer>> map = new LinkedHashMap<>(threads.size()/2);
        for (EsbEncapsulationThread thread: threads) {
            Integer threadOrder = thread.getThreadOrder();
            if(map.containsKey(threadOrder)){
                List<Integer> serviceIds = map.get(threadOrder);
                serviceIds.add(thread.getServiceId());
            } else {
                List<Integer> serviceIds = new ArrayList<>();
                serviceIds.add(thread.getServiceId());
                map.put(threadOrder,serviceIds);
            }
        }
        return map;
    }

    /**
     * 获取线程中关联的接口id数组集合 inputParamsMaps
     */
    private Map<Integer,List<EsbInboundParam>> getParamsMapsList(JSONObject json,List<Integer> serviceIds,
                                                                 List<EsbInboundParam> inboundParams){
        Map<Integer,List<EsbInboundParam>> paramMap = new HashMap<>(serviceIds.size());
        for (EsbInboundParam inboundParam: inboundParams) {
            String key = inboundParam.getParamKey();
            if(json.containsKey(key)){
                String value = String.valueOf(json.get(key));
                inboundParam.setParamValue(value == null ? "" : value);
            }
            Integer serviceId = inboundParam.getServiceId();
            if(paramMap.containsKey(serviceId)){
                List<EsbInboundParam> paramList = paramMap.get(serviceId);
                paramList.add(inboundParam);
            } else {
                List<EsbInboundParam> paramList = new ArrayList<>();
                paramList.add(inboundParam);
                paramMap.put(serviceId,paramList);
            }
        }
        return paramMap;
    }
}
